#pragma once

#include <iostream>
#include <pthread.h>
#include <functional>
#include "Sock.hpp"
#include "Protocol.hpp"

namespace TcpServer_ns
{
    using namespace Protocol_ns;
    class TcpServer;

    using func_t = std::function<Response(const Request &)>;

    class ThreadData
    {
    public:
        ThreadData(int sock, std::string ip, uint16_t port, TcpServer *tsvrp)
            : _sock(sock), _ip(ip), _port(port), _tsvrp(tsvrp)
        {
        }
        ~ThreadData() {}

    public:
        int _sock;
        std::string _ip;
        uint16_t _port;
        TcpServer *_tsvrp; // 服务器对应的指针
    };

    class TcpServer
    {
    public:
        TcpServer(func_t func, uint16_t port)
            : _func(func), _port(port)
        {
        }

        void InitServer() // 服务器初始化
        {
            _listensock.Socket();
            _listensock.Bind(_port);
            _listensock.Listen();

            logMessage(Info, "InitServer done,listensock:%d", _listensock.Fd());
        }

        void Start()
        {
            while (true)
            {
                std::string clientip;
                uint16_t clinetport;
                int fd = _listensock.Accept(&clientip, &clinetport);
                if (fd < 0)
                {
                    continue;
                }
                logMessage(Debug, "get a new client,client inof:[%s:%d]", clientip.c_str(), clinetport);

                pthread_t tid;
                ThreadData *td = new ThreadData(fd, clientip, clinetport, this);
                pthread_create(&tid, nullptr, ThreadRoutine, td);
            }
        }

        static void *ThreadRoutine(void *args)
        {
            pthread_detach(pthread_self()); // 线程分离避免僵尸
            ThreadData *td = static_cast<ThreadData *>(args);
            td->_tsvrp->ServiceIO(td->_sock, td->_ip, td->_port); // 线程内提供服务
            logMessage(Debug, "thread quit, client quit ...");
            delete (td);
            return nullptr;
        }

        void ServiceIO(int sock, std::string &ip, const uint16_t &port) // 读写服务
        {
            // 接收字符串
            // 由于TCP是面向字节流的，如何保证读入的字符串就是对方发送的那一部分，而没有其他非数据部分
            // 即如何保障读取的是一个完整的报文，而不是两个或者半个。并不能保障
            std::string inbuffer;

            while (true)
            {
                std::string package;
                int n = ReadPackage(sock, inbuffer, &package);
                if (n == -1)
                {
                    break;
                }
                else if (n == 0)
                {
                    continue;
                }
                else
                {
                    // 此时package一定是一个完整的报文，获取有效载荷
                    package = RemoveHeader(package, n);

                    // 将字符串反序列化，也就是结构化
                    Request req;
                    req.Deserialization(package);

                    // 接收Request返回Response
                    Response resp = _func(req);

                    // 返回响应给用户
                    std::string send_string;
                    resp.Serialization(&send_string); // 序列化，形成可发送的字符串

                    // 添加报头
                    send_string = AddHeader(send_string);

                    // 发送到网络
                    cout << "send to net" << endl;
                    send(sock, send_string.c_str(), send_string.size(), 0);
                }
            }
        }

        ~TcpServer()
        {
            _listensock.Close();
        }

    private:
        uint16_t _port;
        Sock _listensock; // 监听套接字
        func_t _func;     // 回调函数
    };
}
